package cn.com.pc.penguin.core;

import org.apache.log4j.Logger;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.RAMDirectory;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * Created by IntelliJ IDEA.
 * User: huangqinghe
 * To change this template use File | Settings | File Templates.
 */
public class PenguinIndexer {
    private static final Logger logger = Logger.getLogger(PenguinIndexer.class);
	private static final Object MUTEX = new Object();
	private PenguinSettings settings;
	//private IndexWriter fsWriter;
	private IndexWriter writer;
	private List<NewDocumentAdded> newDocumentAddedList = new ArrayList<NewDocumentAdded>();
	private boolean hasMore = false;

	public PenguinIndexer(PenguinSettings settings) throws Exception {
		this.settings = settings;
		this.createWriter();
	}

	public void watchNewDocuDocumentAdded(NewDocumentAdded newDoc){
		this.newDocumentAddedList.add(newDoc);
	}

	private void createWriter() throws Exception {
		if(this.writer != null) {
			this.writer.close();
		}

		if (settings.isOnRam()) {
			//RAM IndexWriter
			Directory ramDirectory = new RAMDirectory();
			this.writer = new IndexWriter(ramDirectory, this.settings.analyzer(), true,
	                new IndexWriter.MaxFieldLength(25000));
			this.writer.addIndexesNoOptimize(this.settings.directory());
		}else {
			this.writer = new IndexWriter(this.settings.directory(), this.settings.analyzer(), true,
	                new IndexWriter.MaxFieldLength(25000));
		}

		this.notifyNewDocumentAdded();
	}

	public void createIndex(Document doc) throws Exception {
		if(doc != null) {
			synchronized(MUTEX) {
				this.writer.addDocument(doc);
				this.hasMore = true;
			}
		}
	}

	public void createIndex(Collection<Document> docs,Collection<String> ids) throws Exception {
		synchronized(MUTEX) {
			if(ids != null && ids.size() > 0) {
				for(String id : ids) {
					this.writer.deleteDocuments(new TermQuery(new Term("id",id)));
				}
				this.hasMore = true;
			}

			if(docs != null && docs.size() > 0) {
				for(Document doc : docs) {
					this.writer.addDocument(doc);
				}
				this.hasMore = true;
			}
		}
	}

	public void delete(String id) throws Exception {
		synchronized(MUTEX) {
			this.writer.deleteDocuments(new TermQuery(new Term("id",id)));
			this.hasMore = true;
		}
	}

	public void delete(Collection<String> ids) throws Exception {
		if(ids != null && ids.size()>0) {
			synchronized(MUTEX) {
				for(String id : ids) {
					this.writer.deleteDocuments(new TermQuery(new Term("id",id)));
				}
				this.hasMore = true;
			}
		}
	}

	public void commit() throws Exception {
		synchronized(MUTEX) {
			this.writer.optimize();
			this.writer.commit();
			if (settings.isOnRam()) {
				IndexWriter fsWriter = new IndexWriter(this.settings.directory(), this.settings.analyzer(), true,
		                new IndexWriter.MaxFieldLength(25000));
				fsWriter.addIndexesNoOptimize(this.writer.getDirectory());
				fsWriter.commit();
				fsWriter.close();
			}

			this.hasMore = true;
			this.notifyNewDocumentAdded();
		}
	}

	public void notifyNewDocumentAdded() throws Exception{
		synchronized(MUTEX) {
			if(this.hasMore) {
				for(NewDocumentAdded nda : this.newDocumentAddedList) {
					nda.newDocumentAdded(this.writer.getReader());
				}
				this.hasMore = false;
			}
		}
	}

	public void removeLockFile() throws Exception {
		try {
			if (IndexWriter.isLocked(this.settings.directory())) {
				IndexWriter.unlock(this.settings.directory());
			}
		}
		catch (IOException e) {
			throw e;
		}
	}



	public void close() throws Exception {
		this.commit();
	}
}
